<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 如果刚开始先加载A应用生成window.a后，再去加载B应用(可能window.a影响B应用)
        // 沙箱就是创造一个干净的环境给子应用使用，当切换应用时可以选择丢弃和恢复属性。
        // JS沙箱 （proxy,new Func,eval)
        // 1.快照沙箱(一年前拍一张，现在拍一张，将区别保存起来，再回到一年前，把区别应用到一年前)
            // 1.激活时将当前window属性进行快照处理
            // 2.失活时用快照中的内容和当前window属性比对
            // 3.如果属性发生变化保存到modifyPropsMap中，并用快照还原window属性
            // 4.在次激活时，再次进行快照，并用上次修改的结果还原window
            // 快照沙箱只能针对单实例应用场景,如果是多个实例同时挂载的情况则无法解决，只能通过proxy代理沙箱来实现
        // 2.Proxy 代理沙箱（实现多应用沙箱）
            // 每个应用都创建一个proxy来代理window，好处是每个应用都是相对独立，不需要直接更改全局window属性！
        class SnapshotSandbox {
            constructor(){
                this.proxy = window //window属性
                this.modifyPropsMap = {}; // 修改了那些属性
                this.active();
            }
            //激活时
            active(){
                this.windowSnapshot = {} //window对象的快照
                for (const prop in window) {
                    if (Object.hasOwnProperty.call(window, prop)) {
                        // 将window上的属性进行拍照
                        this.windowSnapshot[prop] = window[prop] 
                    }
                }
                // 在次激活时，再次进行快照，并用上次修改的结果还原window
                Object.keys(this.modifyPropsMap).forEach(p => {
                    window[p] = this.modifyPropsMap[p];
                });
            }
            // 失活时
            inactive(){
                for (const prop in window) { 
                    if (Object.hasOwnProperty.call(window, prop)) {
                        // 对比失活和快照的中的内容差异
                        if(window[prop] !== this.windowSnapshot[prop]){
                            // 将失活保存到modifyPropsMap中
                            this.modifyPropsMap[prop] = window[prop]
                            // 用快照还原window属性
                            window[prop] = this.windowSnapshot[prop]
                        }
                    }
                }
            }
        }
        let sandbox = new SnapshotSandbox();
        
        // 应用的运行，从开始到结束，切换后不会影响全局
        ((window) => {
            window.a = 1;
            window.b = 2;
            window.c = 3
            console.log(a,b,c) //1 2 3
            sandbox.inactive();
            console.log(a,b,c) //undefined undefined undefined
            sandbox.active();
            console.log(a,b,c) //1 2 3

        })(sandbox.proxy); //sandbox.proxy就是window
        

    </script>
</body>
</html>